/**************************************************************
  > File Name: mycopy1.c
  > Author: LuoLiang
  > Mail: 1204553475@qq.com 
  > Created Time: 2022年03月06日 星期日 06时13分17秒
 **************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>

#define TTY1 "/dev/tty3"
#define TTY2 "/dev/tty4"

#define BUFSIZE 1024
enum 
{
	STATE_R = 1,
	STATE_W,
STATE_AUTO,
	STATE_EX,
	STATE_T
};

struct fsm_st
{
	int state;
	int sfd;
	int dfd;
	int len;
	int pos;
	char *errstr;
	char buf[BUFSIZE];
};

int fd1, fd2;

static void fsmDriver(struct fsm_st *fsm)
{
	int ret;

	switch (fsm->state)
	{
		case STATE_R:
			fsm->len = read(fsm->sfd, fsm->buf, BUFSIZE);
			if (fsm->len == 0)
				fsm->state = STATE_T;
			else if (fsm->len < 0)
			{
				if (errno == EAGAIN)
				{
					fsm->state = STATE_R;
				}
				else
				{
					fsm->errstr = "read()";
					fsm->state = STATE_EX;
				}
			}
			else
			{
				fsm->pos = 0;
				fsm->state = STATE_W;
			}
			break;
		case STATE_W:
			ret = write(fsm->dfd, fsm->buf + fsm->pos, fsm->len);
			if (ret < 0)
			{
				if (errno == EAGAIN)
				{
					fsm->state = STATE_W;
				}
				else
				{
					fsm->errstr = "write()";
					fsm->state = STATE_EX;
				}
			}
			else
			{
				fsm->pos += ret;
				fsm->len -= ret;
				if (fsm->len == 0)
					fsm->state = STATE_R;
				else
					fsm->state = STATE_W;
			}
			break;
		case STATE_EX:
			perror(fsm->errstr);
			fsm->state = STATE_T;
			break;
		case STATE_T:
			/* do sth*/
			break;
		default:
			abort();
			break;
			
	}
}
static int max(int a, int b)
{
	return a > b ? a : b;
}

static void relay(int fd1, int fd2)
{
	int fd1Save, fd2Save;
	struct fsm_st fsm12, fsm21;
	struct pollfd fds[2];

	fd1Save = fcntl(fd1, F_GETFL);
	fcntl(fd1, F_SETFL, fd1Save | O_NONBLOCK);

	fd2Save = fcntl(fd2, F_GETFL);
	fcntl(fd2, F_SETFL, fd2Save | O_NONBLOCK);
	
	fsm12.state = STATE_R;
	fsm12.sfd = fd1;
	fsm12.dfd = fd2;

	fsm21.state = STATE_R;
	fsm21.sfd = fd2;
	fsm21.dfd = fd1;
	
	fds[0].fd = fd1;
	fds[1].fd = fd2;
	while (fsm12.state != STATE_T || fsm21.state != STATE_T)
	{
		/* 布置任务 */
		fds[0].events = 0;
		if (fsm12.state == STATE_R)
			fds[0].events |= POLLIN;
		if (fsm21.state == STATE_W)
			fds[0].events |= POLLOUT;
		
		fds[1].events = 0;		
		if (fsm21.state == STATE_R)
			fds[1].events |= POLLIN;
		if (fsm12.state == STATE_W)
			fds[1].events |= POLLOUT;
		/* 监视 */	
		if (fsm12.state < STATE_AUTO || fsm21.state < STATE_AUTO)
		{
			while (poll(fds, 2, -1) < 0)
			{
				if (errno == EINTR)
					continue;
				perror("poll()");
				exit(1);
			}
		}
		
		/* 查看监视结果 */
		if ((fds[0].revents & POLLIN) || (fds[1].revents & POLLOUT) || fsm12.state > STATE_AUTO)
			fsmDriver(&fsm12);
		if ((fds[1].revents & POLLIN) || (fds[0].revents & POLLOUT) || fsm21.state > STATE_AUTO)
			fsmDriver(&fsm21);
	}

	fcntl(fd1, F_SETFL, fd1Save);
	fcntl(fd2, F_SETFL, fd2Save);
}

static void handler(int s)
{
	puts("close over");
	close(fd1);
	close(fd2);
	exit(0);
}
		
int main(int argc, char **argv)
{

	fd1 = open(TTY1, O_RDWR | O_NONBLOCK);
	if (fd1 < 0)
	{
		perror("open()");
		exit(1);
	}
	write(fd1, "TTY1\n", 5);
	
	fd2 = open(TTY2, O_RDWR | O_NONBLOCK);
	if (fd2 < 0)
	{
		perror("open()");
		exit(1);
	}
	write(fd2, "TTY2\n", 5);
	
	signal(SIGINT, handler);	
	relay(fd1, fd2);

    exit(0);
}
